The Repository Pattern in ASP.NET Core is a design pattern used to separate business logic from data access logic by providing an abstraction layer over database operations. This pattern improves maintainability, testability, and flexibility in applications by encapsulating database operations in dedicated repository classes.
Feature | Using Repository Pattern | Using DbSet Directly in Controllers |
---|---|---|
Separation of Concerns | ✅ Maintains separation | ❌ Business and data access logic mixed |
Testability | ✅ Easy to mock and test | ❌ Harder to mock DbContext |
Code Reusability | ✅ Common operations are encapsulated | ❌ Repetitive DbSet calls |
Flexibility | ✅ Can switch database providers easily | ❌ Tightly coupled to EF Core |
We will create:
ICustomerRepository
and CustomerRepository
)The Unit of Work (UoW) pattern is a centralized mechanism to manage database transactions and ensure that multiple repository operations are treated as a single unit of execution. It acts as a wrapper around multiple repositories to coordinate their changes and commit them in one go.
SaveChangesAsync()
separately, causing multiple round trips to the database.SaveChangesAsync()
in individual repositories could lead to partial updates if one operation succeeds and another fails.SaveChanges()
NOT Be in the Repository?If each repository calls SaveChangesAsync()
, you lose control over transactions.
Imagine you have two repositories: CustomerRepository
and OrderRepository
.
If you try to add a customer and add an order separately, each calling SaveChangesAsync()
:
var customer = new Customer { Name = "John Doe" };
await _customerRepository.AddAsync(customer);
await _customerRepository.SaveChangesAsync(); // ❌ First database call
var order = new Order { CustomerId = customer.Id, TotalAmount = 100 };
await _orderRepository.AddAsync(order);
await _orderRepository.SaveChangesAsync(); // ❌ Second database call
What happens if the second SaveChangesAsync()
fails?
If each repository calls SaveChangesAsync()
, you end up with multiple database calls instead of batching them into a single transaction.
await _customerRepository.SaveChangesAsync(); // ❌ DB call
await _orderRepository.SaveChangesAsync(); // ❌ Another DB call
Using Unit of Work, all changes can be saved in one go:
await _unitOfWork.SaveChangesAsync(); // ✅ One database call
This reduces network latency and improves database performance.
✔ Unit of Work ensures all database operations are part of a single transaction.
✔ Repositories should NOT call SaveChangesAsync()
to avoid multiple transactions.
✔ EF Core tracks changes, so calling SaveChangesAsync()
once is enough.
✔ Using UoW improves performance, consistency, and maintainability.
--